import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter';
import { embeddingModel, chunkConfig } from './deepseek';
import { qdrantClient } from './db';
import {
  DocumentOperations,
  DocumentChunkOperations,
} from './database-operations';
import { v4 as uuidv4 } from 'uuid';
import { log } from './logger';

// 导出需要的模块
export { embeddingModel, qdrantClient };

// 文档处理服务
export class DocumentProcessor {
  private textSplitter: RecursiveCharacterTextSplitter;
  private collectionName: string;

  constructor() {
    this.textSplitter = new RecursiveCharacterTextSplitter({
      chunkSize: chunkConfig.chunkSize,
      chunkOverlap: chunkConfig.chunkOverlap,
      separators: ['\n\n', '\n', ' ', ''],
    });
    this.collectionName = process.env.QDRANT_COLLECTION_NAME || 'documents';
  }

  // 处理文档：分块、向量化、存储
  async processDocument(
    documentId: string,
    content: string,
    metadata: any = {}
  ): Promise<boolean> {
    try {
      log.info(`开始处理文档: ${documentId}`);

      // 更新文档状态为处理中
      await DocumentOperations.updateStatus(documentId, 'processing');

      // 1. 文本分块
      const chunks = await this.textSplitter.splitText(content);
      log.info(`文档分块完成，共 ${chunks.length} 个块`);

      // 2. 生成嵌入向量
      const embeddings = await this.generateEmbeddings(chunks);
      log.info('向量生成完成');

      // 3. 存储到Qdrant
      const points = chunks.map((chunk, index) => {
        const pointId = uuidv4();
        return {
          id: pointId,
          vector: embeddings[index],
          payload: {
            document_id: documentId,
            chunk_index: index,
            content: chunk,
            metadata: {
              ...metadata,
              chunk_length: chunk.length,
              processed_at: new Date().toISOString(),
            },
          },
        };
      });

      await qdrantClient.upsert(this.collectionName, {
        wait: true,
        points,
      });

      log.info('向量存储到Qdrant完成');

      // 4. 存储块信息到MySQL
      for (let i = 0; i < chunks.length; i++) {
        await DocumentChunkOperations.create(
          documentId,
          i,
          chunks[i],
          points[i].id,
          points[i].payload.metadata
        );
      }

      // 块信息存储到MySQL完成

      // 5. 更新文档状态为完成
      await DocumentOperations.updateStatus(documentId, 'completed');

      // 文档处理完成
      return true;
    } catch (_error) {
      // 文档处理失败
      await DocumentOperations.updateStatus(documentId, 'failed');
      return false;
    }
  }

  // 生成嵌入向量
  private async generateEmbeddings(texts: string[]): Promise<number[][]> {
    try {
      const embeddings = await embeddingModel.embedDocuments(texts);
      return embeddings;
    } catch (error) {
      // 嵌入向量生成失败
      throw error;
    }
  }

  // 搜索相似文档
  async searchSimilarDocuments(
    query: string,
    limit: number = 5,
    threshold: number = 0.7
  ): Promise<unknown[]> {
    try {
      // 生成查询向量
      const queryEmbedding = await embeddingModel.embedQuery(query);

      // 在Qdrant中搜索
      const searchResult = await qdrantClient.search(this.collectionName, {
        vector: queryEmbedding,
        limit,
        score_threshold: threshold,
        with_payload: true,
      });

      return searchResult.map(result => ({
        id: result.id,
        score: result.score,
        document_id: result.payload?.document_id,
        chunk_index: result.payload?.chunk_index,
        content: result.payload?.content,
        metadata: result.payload?.metadata,
      }));
    } catch (error) {
      log.error('相似文档搜索失败', error);
      throw error;
    }
  }

  // 删除文档的所有向量
  async deleteDocumentVectors(documentId: string): Promise<boolean> {
    try {
      // 从Qdrant中删除相关向量
      await qdrantClient.delete(this.collectionName, {
        filter: {
          must: [
            {
              key: 'document_id',
              match: { value: documentId },
            },
          ],
        },
      });

      // 从MySQL中删除块信息
      await DocumentChunkOperations.deleteByDocumentId(documentId);

      // 文档向量删除完成
      return true;
    } catch (_error) {
      // 文档向量删除失败
      return false;
    }
  }

  // 重新处理文档
  async reprocessDocument(documentId: string): Promise<boolean> {
    try {
      // 获取文档信息
      const document = await DocumentOperations.getById(documentId);
      if (!document) {
        throw new Error('文档不存在');
      }

      // 删除旧的向量
      await this.deleteDocumentVectors(documentId);

      // 重新处理
      return await this.processDocument(
        documentId,
        document.content,
        document.metadata
      );
    } catch (_error) {
      // 文档重新处理失败
      return false;
    }
  }

  // 获取处理统计信息
  async getProcessingStats(): Promise<unknown> {
    try {
      const collectionInfo = await qdrantClient.getCollection(
        this.collectionName
      );
      return {
        total_vectors: collectionInfo.points_count,
        collection_name: this.collectionName,
        vector_size: collectionInfo.config.params.vectors?.size || 0,
        distance_metric: collectionInfo.config.params.vectors?.distance || 'cosine',
      };
    } catch (_error) {
      // 获取处理统计信息失败
      return null;
    }
  }
}

// 创建全局实例
export const documentProcessor = new DocumentProcessor();

// 文件处理工具函数
export class FileProcessor {
  // 处理不同类型的文件
  static async extractTextFromFile(file: File): Promise<string> {
    const fileType = file.type;
    const fileName = file.name.toLowerCase();

    try {
      if (fileType === 'text/plain' || fileName.endsWith('.txt')) {
        return await file.text();
      }

      if (fileName.endsWith('.md')) {
        return await file.text();
      }

      // 对于其他文件类型，可以集成更多的文件处理库
      // 例如：pdf-parse, mammoth (for docx), etc.

      throw new Error(`不支持的文件类型: ${fileType}`);
    } catch (error) {
      // 文件文本提取失败
      throw error;
    }
  }

  // 验证文件类型
  static isValidFileType(file: File): boolean {
    const supportedTypes = [
      'text/plain',
      'text/markdown',
      'application/pdf',
      'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    ];

    const supportedExtensions = ['.txt', '.md', '.pdf', '.docx'];

    return (
      supportedTypes.includes(file.type) ||
      supportedExtensions.some(ext => file.name.toLowerCase().endsWith(ext))
    );
  }

  // 验证文件大小
  static isValidFileSize(
    file: File,
    maxSize: number = 10 * 1024 * 1024
  ): boolean {
    return file.size <= maxSize;
  }
}
